package com.luli.beifen;

import com.jcraft.jsch.*;
import java.io.*;
import java.nio.file.*;
import java.nio.file.attribute.BasicFileAttributes;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

public class BackupScheduler {

    // 远程服务器信息
    private static final String REMOTE_HOST = "192.168.175.135";
    private static final int REMOTE_PORT = 22;
    private static final String REMOTE_USER = "root";
    private static final String REMOTE_PASSWORD = "lzp+19991128";
    private static final String REMOTE_DIR = "/YSD/uploadFile";

    // 本地文件备份信息
    private static final String LOCAL_FILE_SOURCE_DIR = "/path/to/local/source";
    private static final String LOCAL_FILE_BACKUP_DIR = "/path/to/local/file/backup";

    // 数据库备份信息
    private static final String DB_USER = "localhost";
    private static final String DB_PASSWORD = "root";
    private static final String DB_NAME = "root";
    private static final String LOCAL_DB_BACKUP_DIR = "/YSD/uploadFile";

    // 定时任务配置
    private static final long INITIAL_DELAY = 0;
    private static final long PERIOD = 24; // 备份周期，单位：小时

    public static void main(String[] args) {
        ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
        scheduler.scheduleAtFixedRate(() -> {
            try {
                // 文件备份
                fullFileBackup();
                incrementalFileBackup();
                differentialFileBackup();

                // 数据库备份
                fullDatabaseBackup();
                // 人大金仓不直接支持增量和差异备份，可结合日志和快照实现类似效果
                // incrementalDatabaseBackup();
                // differentialDatabaseBackup();

                // 传输备份文件到远程服务器
                transferBackupsToRemote();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }, INITIAL_DELAY, PERIOD, TimeUnit.HOURS);
    }

    // 文件全量备份
    private static void fullFileBackup() throws IOException {
        Path sourceDir = Paths.get(LOCAL_FILE_SOURCE_DIR);
        Path backupDir = Paths.get(LOCAL_FILE_BACKUP_DIR, getTimestamp());
        Files.createDirectories(backupDir);

        Files.walkFileTree(sourceDir, new SimpleFileVisitor<Path>() {
            @Override
            public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
                Path target = backupDir.resolve(sourceDir.relativize(file));
                Files.createDirectories(target.getParent());
                Files.copy(file, target, StandardCopyOption.REPLACE_EXISTING);
                return FileVisitResult.CONTINUE;
            }
        });
        System.out.println("文件全量备份完成");
    }

    // 文件增量备份
    private static void incrementalFileBackup() throws IOException {
        Path sourceDir = Paths.get(LOCAL_FILE_SOURCE_DIR);
        Path backupDir = Paths.get(LOCAL_FILE_BACKUP_DIR, getTimestamp() + "_incremental");
        Files.createDirectories(backupDir);

        Files.walkFileTree(sourceDir, new SimpleFileVisitor<Path>() {
            @Override
            public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
                Path lastBackupDir = getLastBackupDir();
                if (lastBackupDir != null) {
                    Path lastBackupFile = lastBackupDir.resolve(sourceDir.relativize(file));
                    if (!Files.exists(lastBackupFile) || Files.getLastModifiedTime(file).compareTo(Files.getLastModifiedTime(lastBackupFile)) > 0) {
                        Path target = backupDir.resolve(sourceDir.relativize(file));
                        Files.createDirectories(target.getParent());
                        Files.copy(file, target, StandardCopyOption.REPLACE_EXISTING);
                    }
                }
                return FileVisitResult.CONTINUE;
            }
        });
        System.out.println("文件增量备份完成");
    }

    // 文件差异备份
    private static void differentialFileBackup() throws IOException {
        incrementalFileBackup(); // 与增量备份逻辑类似
        System.out.println("文件差异备份完成");
    }

    // 数据库全量备份
    private static void fullDatabaseBackup() throws IOException, InterruptedException {
        String backupFilePath = LOCAL_DB_BACKUP_DIR + "/" + getTimestamp() + "_full_backup.dump";
        String command = "kingbase_dump -U " + DB_USER + " -d " + DB_NAME + " -F c -f " + backupFilePath;
        Process process = Runtime.getRuntime().exec(command);
        int exitCode = process.waitFor();
        if (exitCode == 0) {
            System.out.println("数据库全量备份完成");
        } else {
            System.out.println("数据库全量备份失败，退出码: " + exitCode);
        }
    }

    // 获取上次备份目录
    private static Path getLastBackupDir() {
        File backupDir = new File(LOCAL_FILE_BACKUP_DIR);
        File[] backupDirs = backupDir.listFiles(File::isDirectory);
        if (backupDirs != null && backupDirs.length > 0) {
            Arrays.sort(backupDirs, Comparator.comparingLong(File::lastModified).reversed());
            return backupDirs[0].toPath();
        }
        return null;
    }

    // 获取当前时间戳
    private static String getTimestamp() {
        return LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss"));
    }

    // 传输备份文件到远程服务器
    private static void transferBackupsToRemote() throws JSchException, SftpException, IOException {
        JSch jsch = new JSch();
        Session session = jsch.getSession(REMOTE_USER, REMOTE_HOST, REMOTE_PORT);
        session.setPassword(REMOTE_PASSWORD);

        Properties config = new Properties();
        config.put("StrictHostKeyChecking", "no");
        session.setConfig(config);
        session.connect();

        Channel channel = session.openChannel("sftp");
        channel.connect();
        ChannelSftp sftpChannel = (ChannelSftp) channel;

        transferDirectory(Paths.get(LOCAL_FILE_BACKUP_DIR), sftpChannel);
        transferDirectory(Paths.get(LOCAL_DB_BACKUP_DIR), sftpChannel);

        sftpChannel.disconnect();
        channel.disconnect();
        session.disconnect();
        System.out.println("备份文件传输到远程服务器完成");
    }

    // 递归传输目录
    private static void transferDirectory(Path localDir, ChannelSftp sftpChannel) throws SftpException, IOException {
        Files.walkFileTree(localDir, new SimpleFileVisitor<Path>() {
            @Override
            public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
                try {
                    String remotePath = REMOTE_DIR + "/" + localDir.relativize(file).toString().replace("\\", "/");
                    sftpChannel.put(file.toString(), remotePath);
                } catch (SftpException e) {
                    e.printStackTrace();
                }
                return FileVisitResult.CONTINUE;
            }
        });
    }
}